jquery.midcom_services_toolbars.js ➔ attach_events   F
last analyzed

Complexity

Conditions 26

Size

Total Lines 52
Code Lines 37

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 26
eloc 37
c 0
b 0
f 0
dl 0
loc 52
rs 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like jquery.midcom_services_toolbars.js ➔ attach_events often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
$.fn.extend({
2
    midcom_services_toolbar: function(options, items) {
3
        return new $.midcom_services_toolbars(this, options, items);
4
    },
5
    mst_add_item: function(data) {
6
        return this.trigger("add_item",[data]);
7
    },
8
    mst_read_item: function(identifier, options) {
9
        return this.trigger("read_item",[identifier, options]);
10
    },
11
    mst_remove_item: function(object_or_id, options) {
12
        return this.trigger("remove_item",[object_or_id, options]);
13
    },
14
    mst_hide: function() {
15
        return this.trigger("self_hide",[]);
16
    },
17
    mst_show: function() {
18
        return this.trigger("self_show",[]);
19
    }
20
});
21
22
$.midcom_services_toolbars = function(root_element) {
23
    if (root_element.length === 0) {
24
        return;
25
    }
26
27
    var minimizer = $('#midcom_services_toolbars_minimizer'),
28
        default_position = get_default_position(root_element),
29
        memorized_position = get_memorized_position(),
30
        visible = true,
31
        posX = default_position.x,
32
        posY = default_position.y;
33
34
    if (minimizer.length === 0) {
35
        minimizer = $('<div>')
36
            .attr('id', 'midcom_services_toolbars_minimizer')
37
            .prependTo($('body'));
38
    }
39
40
    if (memorized_position != null) {
0 ignored issues
show
Best Practice introduced by
Comparing memorized_position to null using the != operator is not safe. Consider using !== instead.
Loading history...
41
        posX = (memorized_position.x != '' && memorized_position.x != undefined ? memorized_position.x : default_position.x);
0 ignored issues
show
Best Practice introduced by
Comparing memorized_position.x to undefined using the != operator is not safe. Consider using !== instead.
Loading history...
42
        posY = (memorized_position.y != '' && memorized_position.y != undefined ? memorized_position.y : default_position.y);
43
        visible = memorized_position.visible;
44
    }
45
46
    if (parseInt(posY) === 0) {
47
        root_element.addClass('type_menu');
48
    } else {
49
        root_element.addClass('type_palette');
50
51
        if (Math.ceil(posX) + root_element.width() > $(window).width()) {
52
            posX = $(window).width() - (root_element.width() + 4);
53
        }
54
55
        root_element.css({ left: posX + 'px', top: posY + 'px', width: (root_element.width() + 25) + 'px'});
56
    }
57
58
    attach_events();
59
60
    root_element.css({ cursor: 'default' });
61
62
    if (visible === true) {
63
        root_element.show();
64
        minimizer.addClass('toolbar-visible');
65
    } else {
66
        minimizer.addClass('toolbar-hidden');
67
    }
68
69
    function attach_events() {
70
        var item_holder = $('div.items', root_element);
71
72
        $('div.item', item_holder).each(function(i, n) {
73
            var item = $(n),
74
                handle = $('.midcom_services_toolbars_topic_title', item),
75
                children = $('ul', item);
76
77
            item.on('mouseover', function() {
78
                clearTimeout(item_holder.data("hide"));
79
                $('.item ul', item_holder).hide();
80
                $('.midcom_services_toolbars_topic_title.hover', item_holder).removeClass("hover");
81
                handle.addClass("hover");
82
                children.show();
83
            });
84
            item.on('mouseout',function() {
85
                item_holder.data('hide', setTimeout(function() {
86
                    handle.removeClass("hover");
87
                    children.hide();
88
                }, 1000));
89
            });
90
        });
91
92
        minimizer.on('click', toggle_visibility);
93
        root_element.find('.minimizer').on('click', toggle_visibility);
94
95
        root_element.draggable({
96
            start: function() {
97
                if (root_element.hasClass('type_menu')) {
98
                    root_element
99
                        .removeClass('type_menu')
100
                        .addClass('type_palette switch_to_palette');
101
                }
102
            },
103
            drag: function(event, ui) {
104
                if (root_element.hasClass('switch_to_palette')) {
105
                    root_element.removeClass('switch_to_palette');
106
                    //TODO: this should work, but doesn't...
107
                    ui.position.left = $(window).width() - root_element.width();
108
                } else if (ui.position.top === 0) {
109
                    root_element
110
                        .removeClass('type_palette')
111
                        .addClass('type_menu');
112
                }
113
            },
114
            stop: function() {
115
                save_settings(true);
116
            },
117
            containment: 'window',
118
            cancel: '.items ul'
119
        });
120
    }
121
122
    function toggle_visibility(e) {
123
        if (minimizer.hasClass('toolbar-visible')) {
124
            minimizer
125
                .removeClass('toolbar-visible')
126
                .addClass('toolbar-hidden');
127
            root_element.hide();
128
        } else {
129
            minimizer
130
                .removeClass('toolbar-hidden')
131
                .addClass('toolbar-visible');
132
            root_element.show();
133
        }
134
        e.stopPropagation();
135
        save_settings(false);
136
    }
137
138
    function save_settings(save_position) {
139
        if (window.localStorage === undefined || !window.localStorage) {
140
            return false;
141
        }
142
        window.localStorage.setItem('midcom_services_toolbars_visible', (root_element.is(':visible')) ? 'true' : 'false');
143
144
        if (save_position) {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if save_position is false. Are you sure this is correct? If so, consider adding return; explicitly.

This check looks for functions where a return statement is found in some execution paths, but not in all.

Consider this little piece of code

function isBig(a) {
    if (a > 5000) {
        return "yes";
    }
}

console.log(isBig(5001)); //returns yes
console.log(isBig(42)); //returns undefined

The function isBig will only return a specific value when its parameter is bigger than 5000. In any other case, it will implicitly return undefined.

This behaviour may not be what you had intended. In any case, you can add a return undefined to the other execution path to make the return value explicit.

Loading history...
145
            var new_pos = root_element.position();
146
            window.localStorage.setItem('midcom_services_toolbars_x', new_pos.left);
147
            window.localStorage.setItem('midcom_services_toolbars_y', new_pos.top);
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
148
        }
149
    }
150
151
    function get_memorized_position() {
152
        if (window.localStorage === undefined || !window.localStorage) {
153
            return false;
154
        }
155
        return {
156
            visible: window.localStorage.getItem('midcom_services_toolbars_visible') === 'true',
157
            x: window.localStorage.getItem('midcom_services_toolbars_x'),
158
            y: window.localStorage.getItem('midcom_services_toolbars_y')
159
        };
160
    }
161
162
    function get_default_position(re) {
163
        let dw = $(document).width(),
164
            ew = $(re).width();
165
166
        if (ew == 0) {
0 ignored issues
show
Best Practice introduced by
Comparing ew to 0 using the == operator is not safe. Consider using === instead.
Loading history...
167
            return {x: 0, y: 0};
168
        }
169
170
        return {x: (dw / 2) - ew / 2, y: 20};
171
    }
172
};
173